import React from 'react'
import PropTypes from 'prop-types'
import cssStyle from './index.module.css'
import arrow from '@/assets/images/arrow-down.png'

function selectChange(data, parent, replaceProps){  //遍历整个数组，查找对应全选关系，parent存放所有节点信息
    let _data = [...data]
    _data.forEach(item => {
        parent.push(item)
        let hasChildren = item.children !== undefined && Array.isArray(item.children) && item.children.length
        if(hasChildren){  //存在子节点，进行递归，把所有的子节点存入数组
            selectChange(item.children, parent, replaceProps)
        }
    })
    let arr = parent.reverse().filter(item => {  //parent倒叙遍历，即可从子节点往父节点进行遍历，过滤掉无子节点的项
        return item.children !== undefined
    })
    arr.forEach(item => {  //遍历倒叙后的节点，通过数组的引用关系，子节点修改数据后，同样该节点的父节点能拿到最新的子节点数据，直到顶层节点
        let checkedList = item.children.filter(_item => {  //遍历当前所有子节点为选中状态的项
            return _item[replaceProps.checkedType] === 0
        })
        let noCheckedList = item.children.filter(_item => {  //遍历当前所有子节点为未选中状态的项
            return _item[replaceProps.checkedType] === 2
        })
        if(checkedList.length === item.children.length){  //若所有子节点为选中状态，则当前节点为选中状态
            item[replaceProps.checkedType] = 0
        }else if(noCheckedList.length === item.children.length){  //若所有子节点为未选中状态，则当前节点为未选中状态
            item[replaceProps.checkedType] = 2
        }else{  //剩下即是不定选状态
            item[replaceProps.checkedType] = 1
        }
    })
    return _data
}

function TreeComponent(props){
    let li = []
    props.data.forEach((item, index) => {
        let checkedType = item[props.replaceProps.checkedType]
        let hasChildren = (item[props.replaceProps.children] !== undefined && Array.isArray(item[props.replaceProps.children]) && item[props.replaceProps.children].length)
        if(hasChildren){
            li.push(
                <li key={ index } className={ cssStyle.li }>
                    <div className={ cssStyle.item } onClick={ e => { props.slide(item, e) } }>
                        <img src={ arrow } className={ cssStyle.arrow } alt="arrow" />
                        {
                            props.checkBox
                            ?
                            <span
                                className={ cssStyle.checkbox + ' ' + (checkedType === 0 ? cssStyle.checked : (checkedType === 1 ? cssStyle.indeterminate : '')) }
                                onClick={ e => { props.checkboxChange(e, item) } }
                            >
                                <span className={ cssStyle.inner }></span>
                                <input type="checkbox" checked={ checkedType === 0 } onChange={ () => {} } />
                            </span>
                            :
                            null
                        }
                        <span>{ item[props.replaceProps.label] }</span>
                        <div style={{ marginLeft: 'auto' }}>
                            {
                                props.render
                                ?
                                props.render(item)
                                :
                                null
                            }
                        </div>
                    </div>
                    <div className={ cssStyle.slider } style={{ display: 'none' }}>
                        <TreeComponent {...props} data={ item[props.replaceProps.children] } />
                    </div>
                </li>
            )
        }else{
            li.push(
                <li key={ index }>
                    <div className={ cssStyle.item + ' ' + cssStyle.noChildren } onClick={ e => { props.slide(item, e) } }>
                        <img src={ arrow } className={ cssStyle.arrow } alt="arrow" style={{ visibility: 'hidden' }} />
                        {
                            props.checkBox
                            ?
                            <span
                                className={ cssStyle.checkbox + ' ' + (checkedType === 0 ? cssStyle.checked : (checkedType === 1 ? cssStyle.indeterminate : '')) }
                                onClick={ e => { props.checkboxChange(e, item) } }
                            >
                                <span className={ cssStyle.inner }></span>
                                <input type="checkbox" />
                            </span>
                            :
                            null
                        }
                        <span>{ item[props.replaceProps.label] }</span>
                        <div style={{ marginLeft: 'auto' }}>
                            {
                                props.render
                                ?
                                props.render(item)
                                :
                                null
                            }
                        </div>
                    </div>
                </li>
            )
        }
    })
    return (
        <ul className={ cssStyle.tree }>
            { li }
        </ul>
    )
}

TreeComponent.propTypes = {
    marginLeft: PropTypes.number,
    slide: PropTypes.func,
    checkboxChange: PropTypes.func,
    data: PropTypes.array,
    label: PropTypes.string,
    replaceProps: PropTypes.object,
    checkBox: PropTypes.bool,
    render: PropTypes.func
}

class Tree extends React.PureComponent{
    timer = null
    state = {
        data: []
    }
    static getDerivedStateFromProps(nextProps, prevState){
        let data = selectChange(nextProps.data, [], nextProps.replaceProps)
        prevState.data = data
        return prevState
    }
    slide = (item, e) => {
        let el = e.currentTarget.nextElementSibling
        if(el){
            if(this.timer){
                return
            }
            let open = e.currentTarget.nextElementSibling.style.display === 'block' ? true : false
            if(open){
                e.currentTarget.children[0].style.transform = 'rotate(-90deg)'
                let height = el.offsetHeight
                el.style.height = height + 'px'
                this.timer = window.requestAnimationFrame(() => {
                    setTimeout(() => {
                        el.style.height = 0
                        setTimeout(() => {
                            el.style = 'display: none;'
                            this.timer = null
                        }, 300)
                    })
                })
            }else{
                e.currentTarget.children[0].style.transform = 'rotate(0)'
                el.style.display = 'block'
                let height = el.offsetHeight
                el.style.height = 0
                this.timer = window.requestAnimationFrame(() => {
                    setTimeout(() => {
                        el.style.height = height + 'px'
                        setTimeout(() => {
                            el.style = 'display: block;'
                            this.timer = null
                        }, 300)
                    })
                })
            }
        }
        if(this.props.nodeClick){
            this.props.nodeClick(item)
        }
    }
    selectAll = (item, checked) => {  //递归遍历当前所有子节点设置选中状态
        let hasChildren = item.children !== undefined && Array.isArray(item.children) && item.children.length
        if(hasChildren){
            item.children.forEach(item => {
                item[this.props.replaceProps.checkedType] = checked
                this.selectAll(item, checked)
            })
        }
    }
    checkboxChange = (e, item) => {
        let checked = item[this.props.replaceProps.checkedType]
        if(checked === 0){
            checked = 2
        }else{
            checked = 0
        }
        item[this.props.replaceProps.checkedType] = checked
        this.selectAll(item, checked)
        let newData = selectChange(this.state.data, [], this.props.replaceProps)
        this.setState({
            data: newData
        }, () => {
            if(this.props.checkboxChange){
                this.props.checkboxChange(this.state.data)
            }
        })
        e.stopPropagation()
    }
    render(){
        return (
            <div className={ cssStyle.main }>
                <TreeComponent {...this.props} data={ this.state.data } slide={ this.slide } checkboxChange={ this.checkboxChange } />
            </div>
        )
    }
}

Tree.propTypes = {
    match: PropTypes.object,
    data: PropTypes.array,
    nodeClick: PropTypes.func,
    replaceProps: PropTypes.object,
    checkboxChange: PropTypes.func
}

export default Tree